package com.mofum.msdom.excel.annotation.parser.impl;

import com.mofum.msdom.excel.annotation.ATHeaderRow;
import com.mofum.msdom.excel.annotation.ATMergeRange;
import com.mofum.msdom.excel.annotation.ATSheet;
import com.mofum.msdom.excel.annotation.parser.AnnotationParser;
import com.mofum.msdom.excel.metadata.MPHeaderRow;
import com.mofum.msdom.excel.metadata.MPMergeRange;
import com.mofum.msdom.excel.metadata.MPSheet;
import com.mofum.msdom.excel.utils.ReflectUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * AT 工作表注解解析器
 *
 * @author 1615690513@qq.com
 * @since 2018/11/21 0021 15:04
 */
public class ATSheetParser<T> implements AnnotationParser<T, MPSheet> {

    public Map<Field, MPSheet> parseField(T o) {

        Map<Field, MPSheet> map = new HashMap<Field, MPSheet>();

        Field[] fields = ReflectUtils.convertToClass(o).getDeclaredFields();

        for (Field field : fields) {

            if (field.isAnnotationPresent(ATSheet.class)) {

                ATSheet atSheet = field.getAnnotation(ATSheet.class);

                map.put(field, parse(atSheet));

            }

        }

        return map;
    }

    public Map<Type, MPSheet> parseType(T o) {

        Map<Type, MPSheet> map = new HashMap<Type, MPSheet>();

        Class<T> clazz = ReflectUtils.convertToClass(o);

        if (clazz.isAnnotationPresent(ATSheet.class)) {

            ATSheet atSheet = clazz.getAnnotation(ATSheet.class);

            map.put(clazz, parse(atSheet));

        }

        return map;
    }

    public Map<Method, MPSheet> parseMethod(T o) {

        Map<Method, MPSheet> map = new HashMap<Method, MPSheet>();

        Method[] methods = ReflectUtils.convertToClass(o).getDeclaredMethods();

        for (Method method : methods) {

            if (method.isAnnotationPresent(ATSheet.class)) {

                ATSheet atSheet = method.getAnnotation(ATSheet.class);

                map.put(method, parse(atSheet));

            }

        }

        return map;
    }

    public Map<Method, List<MPSheet>> parseParams(T o) {

        Map<Method, List<MPSheet>> map = new HashMap<Method, List<MPSheet>>();

        Method[] methods = ReflectUtils.convertToClass(o).getMethods();

        for (Method method : methods) {

            List<MPSheet> list = new ArrayList<MPSheet>();

            Annotation[][] parameterAnnotations = method.getParameterAnnotations();

            for (Annotation[] parameterAnnotation : parameterAnnotations) {
                for (Annotation annotation : parameterAnnotation) {
                    if (annotation instanceof ATSheet) {
                        ATSheet atSheet = (ATSheet) annotation;
                        list.add(parse(atSheet));
                    }
                }
            }

            map.put(method, list);
        }

        return map;
    }


    public MPSheet parse(ATSheet atSheet) {
        MPSheet mpSheet = new MPSheet();
        mpSheet.setAutoSize(atSheet.autoSize());
        mpSheet.setIndex(atSheet.index());
        mpSheet.setName(atSheet.name());
        mpSheet.setRowHeight(atSheet.rowHeight());
        mpSheet.setLimit(atSheet.limit());
        mpSheet.setOffset(atSheet.offset());
        mpSheet.setColLimit(atSheet.colLimit());
        mpSheet.setColOffset(atSheet.colOffset());
        mpSheet.setFilters(atSheet.filters());

        List<MPMergeRange> list = new ArrayList<MPMergeRange>();
        ATMergeRangeParser<MPMergeRange> parser = new ATMergeRangeParser<MPMergeRange>();

        for (ATMergeRange atMergeRange : atSheet.ranges()) {
            list.add(parser.parse(atMergeRange));
        }

        mpSheet.setRanges(list.toArray(new MPMergeRange[]{}));


        List<MPHeaderRow> headerRows = new ArrayList<MPHeaderRow>();
        ATHeaderRowParser<MPHeaderRow> headerRowParser = new ATHeaderRowParser<>();

        for (ATHeaderRow atHeaderRow : atSheet.headers()) {
            headerRows.add(headerRowParser.parse(atHeaderRow));
        }

        mpSheet.setHeaderRows(headerRows.toArray(new MPHeaderRow[]{}));

        return mpSheet;
    }

}
